<?php

namespace Formax\CLI;

/**
 * 命令行模式任务基础类
 */
abstract class Task extends \Phalcon\CLI\Task
{

    /**
     * 参数管理
     *
     * @var \Formax\Cli\Args
     */
    public $args = null;

    /**
     * 可选参数列表
     *
     * @var array
     */
    protected $_options = array(
        'help' => array(
            'name'        => 'help',
            'short'       => 'h',
            'long'        => 'help',
            'required'    => false,
            'hasValue'    => false,
            'description' => '查看帮助信息',
        )
    );

    /**
     * 默认有效的参数
     *
     * @var array
     */
    protected $_availableOptions = array(
        '-'  => array('h'),    // short option keys
        '--' => array('help'), // long option keys
    );

    /**
     * 注册参数
     *
     *     $this->registerOption('file', 'f', true, true, 'file name required');
     *
     * @param  string            $variableName 参数名称
     * @param  string            $shortKey     短参数名
     * @param  boolean           $required     是否必须
     * @param  boolean           $hasValue     参数需要附带值
     * @param  string            $description  查看帮助时的参数介绍
     * @return \Formax\CLI\Task
     * @throws \Formax\Exception
     */
    public function registerOption($variableName, $shortKey, $required = false, $hasValue = false, $description = '')
    {
        if (in_array($variableName, $this->_availableOptions['--'])) {
            throw new \Formax\Exception("参数 '--$variableName' 已经被注册");
        } elseif (in_array($shortKey, $this->_availableOptions['-'])) {
            throw new \Formax\Exception("短参数 '-$shortKey' 已经被注册");
        }

        $this->_options[$variableName] = array(
            'name'        => $variableName,
            'short'       => $shortKey,
            'long'        => $variableName,
            'required'    => $required,
            'hasValue'    => $hasValue,
            'description' => $description
        );

        $this->_availableOptions['--'][] = $variableName;
        if ($shortKey) {
            $this->_availableOptions['-'][] = $shortKey;
        }

        return $this;
    }

    /**
     * 获取参数详情
     *
     * @param  string  $key     参数名称
     * @param  boolean $isShort 是否短参数
     * @return array
     */
    public function getOptionDetails($key = null, $isShort = true)
    {
        if (! $key) {
            return $this->_options;
        }

        $details = array_filter($this->_options, function ($option) use ($key, $isShort) {
            return $key == $option[$isShort ? 'short' : 'long'];
        });

        return is_array($details) ? current($details) : false;
    }

    /**
     * 显示帮助信息
     *
     * @param string $task
     */
    public function displayHelp($task = null)
    {
        return $this->dispatcher->forward(array(
            'task'   => 'help',
            'params' => array(
                'task' => $task ? $task : $this->dispatcher->getTaskName(),
            ),
        ));
    }

    /**
     * Task 运行前执行
     *
     * @return boolean
     * @throws \Formax\Exception
     */
    public function beforeExecuteRoute()
    {
        $this->args = new \Formax\CLI\Args($this->dispatcher);

        // 如果存在初始化参数的方法，则自动调用
        if (method_exists($this, 'registerOptions')) {
            $this->registerOptions();
        }

        $params = $this->dispatcher->getParam('params');

        try {
            while (list($i, $param) = each($params)) {
                if (
                    preg_match('/(-{1,2})([a-zA-Z]\w*)(=(.*))?/', $param, $matches)
                    && $matches[2] != 'params'
                    && ($option = $this->getOptionDetails($matches[2], $matches[1]=='-'))
                ) {
                    if ($option['name'] == 'help') {
                        $this->displayHelp($this->dispatcher->getTaskName());

                        return false;
                    }

                    if ($option['hasValue'] && ! isset($matches[4])) {
                        if (isset($params[$i + 1]) && substr($params[$i + 1], 0, 1) != '-') {
                            $matches[4] = $params[$i + 1];
                            unset($params[$i + 1]);
                        } else {
                            throw new \Formax\Exception("参数 \"$matches[1]$matches[2]\" 缺少值");
                        }
                    } elseif (! $option['hasValue'] && isset($matches[4])) {
                        throw new \Formax\Exception("标识 \"$matches[2]\" 不需要任何值");
                    }

                    $this->dispatcher->setParam($option['name'], isset($matches[4]) ? $matches[4] : true);
                } else {
                    throw new \Formax\Exception("未知的标识 \"$param\"");
                }
            };

            foreach ($this->_options as $option) {
                if ($option['required'] && $this->dispatcher->getParam($option['name']) === null) {
                    throw new \Formax\Exception('参数 "-'.$option['short'].'" 需要指定。查看帮助信息：' . $this->dispatcher->getTaskName() . ' -h');
                }
            }
        } catch (\Exception $e) {
            cli_error($e->getMessage());
        }

        return true;
    }

}
